package com.tyq.auth.security.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tyq.auth.common.ResultData;
import com.tyq.auth.oauth2.Oauth2AuthorizationServerConfig;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义登录成功处理器
 *
 * @author 谭永强
 * @date 2024-05-20
 */
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    /**
     * Token前缀
     */
    private static final String TOKEN_PREFIX = "Basic ";
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private ClientDetailsService clientDetailsService;
    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;
    @Resource
    private TokenStore tokenStore;
    @Resource
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Resource
    private Oauth2AuthorizationServerConfig authorizationServerConfig;

    /**
     * 当用户已成功通过身份验证时调用。
     *
     * @param request        导致身份验证成功的请求
     * @param response       响应
     * @param authentication 在身份验证过程中创建的身份验证对象
     * @throws IOException      IO异常
     * @throws ServletException Servlet异常
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        //此处处理登录成功后的逻辑
        String header = request.getHeader("Authorization");
        String[] tokens = extractAndDecodeHeader(header);
        assert tokens.length == 2;
        String clientId = tokens[0];
        String clientSecret = tokens[1];
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        TokenRequest tokenRequest = new TokenRequest(new HashMap<>(), clientDetails.getClientId(), clientDetails.getScope(), "custom");
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
        User user = (User) authentication.getPrincipal();
        oAuth2Authentication.setDetails(user);
        AuthorizationServerTokenServices serverTokenServices = authorizationServerConfig.tokenServices();
        //判断该用户是否在该终端已登录
        OAuth2AccessToken token = serverTokenServices.getAccessToken(oAuth2Authentication);
        if (token == null) {
            System.out.println("创建token");
            //如果用户未登录，则生成新的token
            token = serverTokenServices.createAccessToken(oAuth2Authentication);
        } else {
            System.out.println("刷新token");
            //如果用户已登录，就直接刷新token，会删除旧token的同时生成新token
            token = serverTokenServices.refreshAccessToken(token.getRefreshToken().getValue(), tokenRequest);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("userInfo", user);
        map.put("token", token);
        ResultData<Map<String, Object>> resultData = new ResultData<>();
        resultData.setSuccess(true);
        resultData.setMessage("登录成功");
        resultData.setResult(map);
        objectMapper.writeValue(response.getWriter(), resultData);
    }

    private String[] extractAndDecodeHeader(String header) {
        byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8);
        byte[] decoded;
        try {
            decoded = Base64.getDecoder().decode(base64Token);
        } catch (IllegalArgumentException var7) {
            throw new BadCredentialsException("Failed to decode basic authentication token");
        }
        String token = new String(decoded, StandardCharsets.UTF_8);
        int delim = token.indexOf(":");
        if (delim == -1) {
            throw new BadCredentialsException("Invalid basic authentication token");
        } else {
            return new String[]{token.substring(0, delim), token.substring(delim + 1)};
        }
    }
}